package com.appcenter.autotask.controller;

import com.appcenter.autotask.input.*;
import com.appcenter.autotask.model.JobAndTrigger;
import com.appcenter.autotask.output.LoadJobOutput;
import com.appcenter.autotask.output.QueryJobOutput;
import com.appcenter.autotask.service.BaseJob;
import com.appcenter.autotask.service.HttpAPIService;
import com.appcenter.autotask.service.IJobAndTriggerService;
import com.appcenter.autotask.tool.DateUnit;
import com.appcenter.jz.Logger.BusinessLogger;
import com.appcenter.jz.Logger.LoggerGenre;
import com.appcenter.jz.config.ErrorJsonResult;
import com.appcenter.jz.config.JsonResult;
import com.appcenter.jz.page.PagedResult;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

import static org.quartz.DateBuilder.futureDate;

/**
 * Created by haoxy on 2018/9/28.
 * E-mail:hxyHelloWorld@163.com
 * github:https://github.com/haoxiaoyong1014
 */
@RestController
@RequestMapping("api/services/autotaskservice/autotask")
@Api("应用操作API")
public class JobController {

    @Autowired
    private IJobAndTriggerService iJobAndTriggerService;
    //加入Qulifier注解，通过名称注入bean
    @Autowired
    @Qualifier("Scheduler")
    private Scheduler scheduler;
    @Autowired
    private DateUnit dateUnit;
    private static Logger log = LoggerFactory.getLogger(JobController.class);

    @Autowired
    private HttpAPIService httpAPIService;


    /**
     * 添加任务
     *
     * @param input
     * @throws Exception
     */
    @ApiOperation(value = "创建任务", notes = "创建任务",produces = "application/json")
    @PostMapping("/addjob")
    public ResponseEntity<JsonResult> addjob(@RequestBody AddJobInput input) throws Exception {
        JsonResult r = new JsonResult();
        try {
            if ("".equals(input.getJobClassName()) || "".equals(input.getJobGroupName()) || "".equals(input.getCronExpression())) {
               throw new ErrorJsonResult("10000031","发现空值");
            }
            if (input.getTimeType() == null) {
                addCronJob(input);
                r.setResult(true);
                return ResponseEntity.ok(r);
            }
            addSimpleJob(input);
            BusinessLogger.Info(LoggerGenre.Add, "添加自动任务", input);
            r.setResult(true);
        } catch (ErrorJsonResult e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setError(e);
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);
    }

    //CronTrigger
    public void addCronJob(AddJobInput input) throws Exception {

        // 启动调度器
        scheduler.start();

        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(getClass(input.getJobClassName()).getClass()).
                withIdentity(input.getJobClassName(), input.getJobGroupName())
                .build();

        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(input.getCronExpression());
        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().
                withIdentity(input.getJobClassName(), input.getJobGroupName())
                .withSchedule(scheduleBuilder)
                .build();

        try {
            scheduler.scheduleJob(jobDetail, trigger);

        } catch (SchedulerException e) {
            System.out.println("创建定时任务失败" + e);
            throw new Exception("创建定时任务失败");
        }
    }

    //Simple Trigger
    public void addSimpleJob(AddJobInput input) throws Exception {
        // 启动调度器
        scheduler.start();

        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(getClass(input.getJobClassName()).getClass())
                .withIdentity(input.getJobClassName(), input.getJobGroupName())
                .build();

        DateBuilder.IntervalUnit verDate = dateUnit.verification(input.getTimeType());
        SimpleTrigger simpleTrigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                .withIdentity(input.getJobClassName(), input.getJobGroupName())
                .startAt(futureDate(Integer.parseInt(input.getCronExpression()), verDate))
                .forJob(input.getJobClassName(), input.getJobGroupName())
                .build();

        try {
            scheduler.scheduleJob(jobDetail, simpleTrigger);

        } catch (SchedulerException e) {
            System.out.println("创建定时任务失败" + e);
            throw new Exception("创建定时任务失败");
        }
    }

    /**
     * 暂停任务
     *
     * @param input
     * @throws Exception
     */
    @ApiOperation(value = "暂停任务", notes = "暂停任务",produces = "application/json")
    @PostMapping("/pausejob")
    public ResponseEntity<JsonResult> pausejob(@RequestBody PauseJobInput input) throws Exception {
        JsonResult r = new JsonResult();
        try {
            jobPause(input.getJobClassName(), input.getJobGroupName());
            BusinessLogger.Info(LoggerGenre.Pause, "暂停自动任务", input);
            r.setResult(true);
        } catch (ErrorJsonResult e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setError(e);
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);

    }

    public void jobPause(String jobClassName, String jobGroupName) throws Exception {
        scheduler.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
    }

    /**
     * 恢复任务
     *
     * @param input
     * @throws Exception
     */
    @ApiOperation(value = "恢复任务", notes = "恢复任务",produces = "application/json")
    @PostMapping("/resumejob")
    public ResponseEntity<JsonResult> resumejob(@RequestBody ResumeJobInput input) throws Exception {
        JsonResult r = new JsonResult();
        try {
            jobresume(input.getJobClassName(), input.getJobGroupName());
            BusinessLogger.Info(LoggerGenre.Resume, "恢复自动任务", input);
            r.setResult(true);
        } catch (ErrorJsonResult e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setError(e);
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);


    }

    public void jobresume(String jobClassName, String jobGroupName) throws Exception {
        scheduler.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
    }

    /**
     * 更新任务
     *
     * @param input
     * @throws Exception
     */
    @ApiOperation(value = "更新任务", notes = "更新任务",produces = "application/json")
    @PostMapping("/reschedulejob")
    public ResponseEntity<JsonResult> rescheduleJob(@RequestBody RescheduleJobInput input) throws Exception {
        JsonResult r = new JsonResult();
        try {
            jobreschedule(input.getJobClassName(), input.getJobGroupName(), input.getCronExpression());
            BusinessLogger.Info(LoggerGenre.Update, "更新自动任务", input);
            r.setResult(true);
        } catch (ErrorJsonResult e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setError(e);
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);
    }

    public void jobreschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            System.out.println("更新定时任务失败" + e);
            throw new Exception("更新定时任务失败");
        }
    }

    /**
     * 删除任务
     * 删除操作前应该暂停该任务的触发器，并且停止该任务的执行
     *
     * @param input
     * @throws Exception
     */
    @ApiOperation(value = "删除任务", notes = "删除任务",produces = "application/json")
    @PostMapping("/deletejob")
    public ResponseEntity<JsonResult> deletejob(@RequestBody DeleteJobInput input) throws Exception {
        JsonResult r = new JsonResult();
        try {
            jobdelete(input.getJobClassName(), input.getJobGroupName());
            BusinessLogger.Info(LoggerGenre.Delete, "删除自动任务", input);
            r.setResult(true);
        } catch (ErrorJsonResult e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setError(e);
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);
    }
    public void jobdelete(String jobClassName, String jobGroupName) throws Exception {
        scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
        scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
        scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
    }

    /**
     * 查询任务
     *
     * @param input
     * @return
     */
    @ApiOperation(value = "查询任务", notes = "查询任务",produces = "application/json")
    @PostMapping("/queryjob")
    public ResponseEntity<JsonResult> queryjob(@RequestBody QueryJobInput input) {
        JsonResult r = new JsonResult();
        try {
            PageInfo<JobAndTrigger> page = iJobAndTriggerService.getJobAndTriggerDetails(input.getPage().getPageNo(), input.getPage().getPageSize());
            QueryJobOutput output = new QueryJobOutput();
            BusinessLogger.Info(LoggerGenre.View, "获取自动任务", input);
            output.setItems(new PagedResult<JobAndTrigger>(page.getList(), (int) page.getTotal()));
            r.setResult(output);
        } catch (Exception e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);
    }

    /**
     * 加载任务
     *
     * @param input
     * @return
     */
    @ApiOperation(value = "加载任务", notes = "加载任务",produces = "application/json")
    @PostMapping("/loadjob")
    public ResponseEntity<JsonResult> loadJob(@RequestBody LoadJob input) {
        JsonResult r = new JsonResult();
        try {
            PageInfo<JobAndTrigger> page = iJobAndTriggerService.getJobAndTriggerDetails(input.getPage().getPageNo(), input.getPage().getPageSize());
            LoadJobOutput output = new LoadJobOutput();
            output.setItems(new PagedResult<JobAndTrigger>(page.getList(), (int) page.getTotal()));
            r.setResult(output);
        } catch (ErrorJsonResult e) {
            r.setResult(e.getClass().getName() + ":" + e.getMessage());
            r.setError(e);
            e.printStackTrace();
            return ResponseEntity.status(500).body(r);
        }
        return ResponseEntity.ok(r);
    }



    /**
     * 根据类名称，通过反射得到该类，然后创建一个BaseJob的实例。
     * 由于NewJob和HelloJob都实现了BaseJob，
     * 所以这里不需要我们手动去判断。这里涉及到了一些java多态调用的机制
     *
     * @param classname
     * @return
     * @throws Exception
     */
    public static BaseJob getClass(String classname) throws Exception {
        Class<?> class1 = Class.forName(classname);
        return (BaseJob) class1.newInstance();
    }

}
